﻿using System;
using System.Collections.Generic;
using System.Text;
using FIRADriverLibrary;
using RoBOSSCommunicator;
using RobotRace.engine.robossConnector.exceptions;

namespace RobotRace.engine.robossConnector
{
    public class RobossConnector
    {
        private static volatile RobossConnector instance;

        private Communicator communicator;
        private FIRADriver firaDriver;
        private string ip;
        private string port;

        public static RobossConnector getConnector(String ip, String port)
        {
            if (instance == null)
            {
                instance = new RobossConnector(ip, port);
            }
            return instance;
        }

        public static RobossConnector getConnector()
        {
            return instance;
        }

        private RobossConnector(String ip, String port)
        {
            this.ip = ip;
            this.port = port;
            firaDriver = new FIRADriver();
            communicator = new Communicator();
            if (firaDriver.ConnectToRoBOSS(ip, port) < 0)
            {
                throw new ConnectionException("An error occured while connecting to RoBOSS:\n" + FIRADriver.lastError);
            }
            if (communicator.Connect(ip, port) < 0)
            {
                throw new ConnectionException("An error occured while connecting to RoBOSS:\n" + Communicator.lastError);
            }

        }

        public FIRARobotState[] getRobots()
        {
            return firaDriver.firaRobots;
        }

        public Geom[] getWorldDefinition()
        {
            return communicator.environmentGeoms;
        }

        public void requestRobot(FIRARobotState robot)
        {
            Console.WriteLine("Trying to acquire robot with ID: " + robot.portId);
            if (firaDriver.RequestRobot(robot.portId) < 0)
            {
                Console.WriteLine("FAILED!");
                Console.WriteLine("Last error: " + FIRADriver.lastError);
                throw new RobotAcquireException(FIRADriver.lastError);
            }
            else
            {
                Console.WriteLine("Robot with Id " + robot.portId + " successfully requested");
            }
        }

        public void releaseRobot(FIRARobotState robot)
        {
            Console.WriteLine("Releasing robot with ID: " + robot.portId);
            if (firaDriver.ReleaseRobot(robot.portId) < 0)
            {
                Console.WriteLine("FAILED!");
                Console.WriteLine("Last error: " + FIRADriver.lastError);
                throw new RobotAcquireException(FIRADriver.lastError);
            }
            else
            {
                Console.WriteLine("Robot with Id " + robot.portId + " successfully released");
            }
        }

        public FIRADriver getFiraDriver()
        {
            return firaDriver;
        }

        public Communicator getCommunicator()
        {
            return communicator;
        }

        ~RobossConnector()
        {
            if (communicator != null)
            {
                communicator.Dispose();
            }
            if (firaDriver != null)
            {
                firaDriver.Dispose();
            }
        }

        public void releaseAllOwnedRobots()
        {
            foreach (FIRARobotState robot in getRobots())
            {
                if (robot.owned)
                {
                    releaseRobot(robot);
                }
            }
        }

        public void requestAllRobots()
        {
            foreach (FIRARobotState robot in getRobots())
            {
                if (!robot.owned)
                {
                    requestRobot(robot);
                }
            }
        }
    }
}
